/*
 * Copyright (c) 2020-2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "spi_stm32l4xx.h"



#define HDF_LOG_TAG spi_hi35xx




#define Stm32xxSpiCntlr_ONE_BYTE 1
#define Stm32xxSpiCntlr_TWO_BYTE 2

static inline uint8_t Stm32xxSpiCntlrToByteWidth(uint8_t bitsPerWord)
{
    if (bitsPerWord <= BITS_PER_WORD_EIGHT) {
        return Stm32xxSpiCntlr_ONE_BYTE; 
    } else {
        return Stm32xxSpiCntlr_TWO_BYTE;
    }
}

static int32_t Stm32xxSpiCntlrSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
    // struct Stm32xxSpiCntlr *stm32xx = NULL;
    printf("nothing to do\n");    
    return 0;
}

static int32_t Stm32xxSpiCntlrGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
    // struct Stm32xxSpiCntlr *stm32xx = NULL;
    printf("nothing to do\n");
    return HDF_SUCCESS;
}

static int32_t Stm32xxSpiCntlrTxRx(const struct Stm32xxSpiCntlr *stm32xx, const struct SpiMsg *msg)
{
    int32_t ret;
    uint32_t tmpLen;
    uint32_t len = msg->len;
    const uint8_t *tx = msg->wbuf;
    uint8_t *rx = msg->rbuf;
    // uint8_t bytes = Pl022ToByteWidth(pl022->bitsPerWord);
    // uint32_t burstSize = pl022->fifoSize * bytes;

    if (tx == NULL && rx == NULL) {
        printf("tx == NULL && rx == NULL \n");
        return HDF_ERR_INVALID_PARAM;
    }

    // if (pl022->transferMode == SPI_INTERRUPT_TRANSFER && RX_INT_FIFO_LEVEL < pl022->fifoSize) {
    //     burstSize = RX_INT_FIFO_LEVEL * bytes;
    // } 
    // printf("tx:%x,len %d\n",*tx,len);

    ret = HAL_SPI_TransmitReceive(stm32xx->spiHandle,tx,rx,len,0xFFFF);
    // ret = HAL_SPI_Transmit(stm32xx->spiHandle,tx,len,0xFFFF);
    if (ret != HAL_OK) {
        printf("%s,TransmitReceive failed\n",__func__);
        return HDF_FAILURE;
    }
    // ret = HAL_SPI_Receive(stm32xx->spiHandle,rx,len,0xFFFF);
    // if (ret != HAL_OK) {
    //     printf("%s,Receive failed\n",__func__);
    //     return HDF_FAILURE;
    // }
    // printf("tx:%x,len %d rx:%x\n",*tx,len,*rx);
    // for (/* tmpLen = 0,  */len = msg->len; len > 0; len -= 1 /* tmpLen */) {
    //     // tmpLen = (len > burstSize) ? burstSize : len;
    //     // if (pl022->transferMode == SPI_INTERRUPT_TRANSFER && tmpLen == burstSize) {
    //     //     OSAL_WRITEL(SPI_ALL_IRQ_ENABLE, (uintptr_t)(pl022->regBase) + REG_SPI_IMSC);
    //     // }
    //     Pl022WriteFifo(pl022, tx, tmpLen);
    //     tx = (tx == NULL) ? NULL : tx + tmpLen;
    //     if (pl022->transferMode == SPI_INTERRUPT_TRANSFER && tmpLen == burstSize) {
    //         ret = OsalSemWait((struct OsalSem *)(&pl022->sem), RX_INT_WAIT_TIMEOUT);
    //     } else {
    //         ret = Pl022CheckTimeout(pl022);
    //     }

    //     if (ret != HDF_SUCCESS) {
    //         HDF_LOGE("%s: %s timeout", __func__, (pl022->transferMode == SPI_INTERRUPT_TRANSFER) ?
    //             "wait rx fifo int" : "wait tx fifo idle");
    //         return ret;
    //     }

    //     Pl022ReadFifo(pl022, rx, tmpLen);
    //     rx = (rx == NULL) ? NULL : (rx + tmpLen);
    // }
    return 0;
}

static int32_t Stm32xxSpiCntlrSetCs(struct Stm32xxSpiCntlr *stm32xx, uint32_t cs, uint32_t flag)
{
    static uint8_t dontChange = 0;
    if (cs != STM32L4R9_GPIOG_PIN8 ) { //此处判断Cs是否合法，比如说大于最大值等等
        return HDF_FAILURE;
    }
    if (flag == SPI_CS_ACTIVE) {
        if(dontChange == 1) {
            return 0;
        } else {
            HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_RESET);//CS_ENABLE(); 
            dontChange = 1;
        printf("CS_ENABLE\n");
        }
    } else {
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_SET);//CS_DISABLE();
        dontChange = 0;
        printf("CS_DISABLE\n");
    }
    return 0;
}

static int32_t Stm32xxSpiCntlrTransferOneMessage(struct Stm32xxSpiCntlr *stm32xx, struct SpiMsg *msg)
{
    int32_t ret;

    // ret = Stm32xxSpiCntlrConfig(stm32xx);//检查参数是否正确

    ret = Stm32xxSpiCntlrSetCs(stm32xx, stm32xx->cntlr->curCs, SPI_CS_ACTIVE);//CS_ENABLE();   

    ret = Stm32xxSpiCntlrTxRx(stm32xx, msg);

    if (ret || msg->csChange) {
        Stm32xxSpiCntlrSetCs(stm32xx, stm32xx->cntlr->curCs, SPI_CS_INACTIVE);//CS_DISABLE();   
    }
    return ret;
}

static int32_t Stm32xxSpiCntlrTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count)
{
    int32_t ret = HDF_FAILURE; 
    struct Stm32xxSpiCntlr *stm32xx = NULL;
    

    if (cntlr == NULL || cntlr->priv == NULL) {
        printf("%s: invalid controller\n", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }
    if (msg == NULL || (msg->rbuf == NULL && msg->wbuf == NULL) || count == 0) {
        printf("%s: invalid parameter\n", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    stm32xx = (struct Stm32xxSpiCntlr *)cntlr->priv;
    
    // stm32xx->mode           = dev->cfg.mode;
    // stm32xx->transferMode   = dev->cfg.transferMode;
    // stm32xx->bitsPerWord    = dev->cfg.bitsPerWord;
    // stm32xx->maxSpeedHz     = dev->cfg.maxSpeedHz; 
    for (uint32_t i = 0; i < count; i++) {
        ret = Stm32xxSpiCntlrTransferOneMessage(stm32xx, &(msg[i]));
        if (ret != 0) {
            printf("%s: transfer error\n", __func__);
            goto __ERR;
        }
    }
__ERR:
    return ret;
}



int32_t Stm32xxSpiCntlrOpen(struct SpiCntlr *cntlr)
{
    // (void)cntlr;
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    printf("entering %s\n",__func__);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

    // printf("busNum: %d , curCs: %d\n",cntlr->busNum,cntlr->curCs);
    switch (cntlr->busNum)
    {
    case 2:
        __HAL_RCC_GPIOA_CLK_ENABLE();
        GPIO_InitStruct.Pin = SPI2_CS_Pin;
        HAL_GPIO_Init(SPI2_CS_GPIO_Port, &GPIO_InitStruct);
        HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin  , GPIO_PIN_SET);

        printf("1\n");
        //打开stm32l4r9-Disco上的MFX，这样才能对外使用SPI2接口
        if (BSP_IO_Init() == IO_ERROR)
        {
            printf("BSP error\n");
            BSP_ErrorHandler();
        }
        printf("2\n");
        BSP_IO_ConfigPin(IO_PIN_6 | IO_PIN_7, IO_MODE_OUTPUT);
        BSP_IO_WritePin(IO_PIN_6 | IO_PIN_7, GPIO_PIN_RESET);
        __HAL_RCC_I2C1_CLK_ENABLE();

        break;
    
    default:
        return HDF_FAILURE;
        break;
    }

    //初始化slaveDevice的片选IO
    switch (cntlr->curCs)
    {
    case STM32L4R9_GPIOG_PIN8:
        __HAL_RCC_GPIOG_CLK_ENABLE();
        GPIO_InitStruct.Pin = GPIO_PIN_8;  //device CS
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
        HAL_GPIO_WritePin(GPIOG, GPIO_PIN_8, GPIO_PIN_SET);//先拉高设备的CS
        break;
    
    default: 
        return HDF_FAILURE; 
        break;
    }
   
    printf("exit %s\n",__func__);
    return HDF_SUCCESS;
}

int32_t Stm32xxSpiCntlrClose(struct SpiCntlr *cntlr)
{
    switch (cntlr->busNum)
    {
    case 2:
        HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin  , GPIO_PIN_RESET);
        HAL_GPIO_DeInit(SPI2_CS_GPIO_Port, SPI2_CS_Pin);

        BSP_IO_WritePin(IO_PIN_6 | IO_PIN_7, GPIO_PIN_SET); //change io function
        break;
    
    default:
        return HDF_FAILURE;
        break;
    }

    switch (cntlr->curCs)
    {
    case STM32L4R9_GPIOG_PIN8:
        HAL_GPIO_DeInit(GPIOG, GPIO_PIN_8);
        break;
    
    default:
        return HDF_FAILURE; 
        break;
    }

    return HDF_SUCCESS;
}



struct SpiCntlrMethod g_method = {
    .Transfer = Stm32xxSpiCntlrTransfer,
    .SetCfg = Stm32xxSpiCntlrSetCfg,
    .GetCfg = Stm32xxSpiCntlrGetCfg,
    .Open = Stm32xxSpiCntlrOpen,
    .Close = Stm32xxSpiCntlrClose,
};


SPI_HandleTypeDef *Stm32l4xxGetSpiInstance(uint32_t busNum)
{
    // printf("SPI_HandleTypeDef : %d \n",busNum);
    if (busNum < 1 || busNum > 4) {
        return NULL;
    }
    switch (busNum) {
        case 2:
            return SPI2; 
        default:
            break;
    }
    return NULL;
}

static int32_t SpiGetBaseCfgFromHcs(struct Stm32xxSpiCntlr *stm32xxSpi, const struct DeviceResourceNode *node)
{
    struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);

    if (iface == NULL ||  iface->GetUint32 == NULL) {
        printf("%s: face is invalid\n", __func__);
        return HDF_FAILURE;
    }
    
    if (iface->GetUint32(node, "busNum", &stm32xxSpi->busNum, 0) != HDF_SUCCESS) {
        printf("%s: read busNum fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "stm32l4SpiCs", &stm32xxSpi->stm32l4SpiCs, 0) != HDF_SUCCESS) {
        printf("%s: read stm32l4SpiCs fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "Mode", &stm32xxSpi->spiHandle->Init.Mode, 0) != HDF_SUCCESS) {
        printf("%s: read Mode fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "Direction", &stm32xxSpi->spiHandle->Init.Direction, 0) != HDF_SUCCESS) {
        printf("%s: read Direction fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "DataSize", &stm32xxSpi->spiHandle->Init.DataSize, 0) != HDF_SUCCESS) {
        printf("%s: read DataSize fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "CLKPolarity", &stm32xxSpi->spiHandle->Init.CLKPolarity, 0) != HDF_SUCCESS) {
        printf("%s: read CLKPolarity fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "CLKPhase", &stm32xxSpi->spiHandle->Init.CLKPhase, 0) != HDF_SUCCESS) {
        printf("%s: read CLKPhase fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "NSS", &stm32xxSpi->spiHandle->Init.NSS, 0) != HDF_SUCCESS) {
        printf("%s: read NSS fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "BaudRatePrescaler", &stm32xxSpi->spiHandle->Init.BaudRatePrescaler, 0) != HDF_SUCCESS) {
        printf("%s: read BaudRatePrescaler fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "FirstBit", &stm32xxSpi->spiHandle->Init.FirstBit, 0) != HDF_SUCCESS) {
        printf("%s: read FirstBit fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "TIMode", &stm32xxSpi->spiHandle->Init.TIMode, 0) != HDF_SUCCESS) {
        printf("%s: read TIMode fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "CRCCalculation", &stm32xxSpi->spiHandle->Init.CRCCalculation, 0) != HDF_SUCCESS) {
        printf("%s: read CRCCalculation fail\n", __func__);
        return HDF_FAILURE;
    }
    if (iface->GetUint32(node, "CRCPolynomial", &stm32xxSpi->spiHandle->Init.CRCPolynomial, 0) != HDF_SUCCESS) {
        printf("%s: read CRCPolynomial fail\n", __func__);
        return HDF_FAILURE;
    }
    
    return 0;
}

static int32_t Stm32xxSpiCntlrInit(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
{
    int32_t ret;
    struct Stm32xxSpiCntlr *stm32xx = NULL;
    SPI_HandleTypeDef *spiHandle = NULL;

    if (device->property == NULL) {
        printf("%s: property is NULL\n", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    stm32xx = (struct Stm32xxSpiCntlr *)OsalMemCalloc(sizeof(*stm32xx));
    if (stm32xx == NULL) {
        printf("%s: OsalMemCalloc error\n", __func__);
        return HDF_FAILURE;
    }
    spiHandle = (struct SPI_HandleTypeDef *)OsalMemCalloc(sizeof(*spiHandle)); 
    stm32xx->spiHandle = spiHandle;

    ret = SpiGetBaseCfgFromHcs(stm32xx, device->property);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: SpiGetBaseCfgFromHcs error\n", __func__);
        OsalMemFree(spiHandle);
        OsalMemFree(stm32xx);
        return HDF_FAILURE;
    }

    spiHandle->Instance = Stm32l4xxGetSpiInstance(stm32xx->busNum);
    if (spiHandle->Instance == NULL) {
        printf("%s: get inst of busNum:%u failed\n", __func__, stm32xx->busNum); 
        return HDF_FAILURE;
    }
    if (HAL_SPI_Init(stm32xx->spiHandle) != HAL_OK) {
        Error_Handler();
    }

    stm32xx->cntlr = cntlr;
    printf("stm32xx->cntlr address :%x\n",stm32xx->cntlr);
    cntlr->priv = stm32xx;
    cntlr->busNum = stm32xx->busNum;
    cntlr->method = &g_method;

    ret = OsalSemInit(&stm32xx->sem, 0);
    if (ret != HDF_SUCCESS) {
        OsalMemFree(stm32xx);
        return ret;
    }
     
    return 0;
}

static void Stm32xxSpiCntlrRemove(struct Stm32xxSpiCntlr *stm32xx)
{
    OsalMemFree(stm32xx->spiHandle);
    OsalMemFree(stm32xx);
}


static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
{
    printf("%s: entry\n", __func__);
    if (device == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }
    return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
}

static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct SpiCntlr *cntlr = NULL;

    printf("%s: entry\n", __func__);
    if (device == NULL) {
        printf("%s: ptr is null\n", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }
    cntlr = SpiCntlrFromDevice(device);
    if (cntlr == NULL) {
        printf("%s: cntlr is null\n", __func__);
        return HDF_FAILURE;
    }

    ret = Stm32xxSpiCntlrInit(cntlr, device);
    if (ret != 0) {
        printf("%s: error init\n", __func__);
        return HDF_FAILURE;
    }
    return ret;
}

static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
{
    struct SpiCntlr *cntlr = NULL;

    printf("%s: entry\n", __func__);
    if (device == NULL) {
        printf("%s: device is null\n", __func__);
        return;
    }
    cntlr = SpiCntlrFromDevice(device);
    if (cntlr == NULL) {
        printf("%s: cntlr is null\n", __func__);
        return;
    }
    if (cntlr->priv != NULL) {
        Stm32xxSpiCntlrRemove((struct Stm32xxSpiCntlr *)cntlr->priv);
    }
    SpiCntlrDestroy(cntlr);
}

struct HdfDriverEntry g_hdfSpiDevice = {
    .moduleVersion = 1,
    .moduleName = "stm32l4xx_spi_driver",
    .Bind = HdfSpiDeviceBind,
    .Init = HdfSpiDeviceInit,
    .Release = HdfSpiDeviceRelease,
};
HDF_INIT(g_hdfSpiDevice);
